/**
 * ts基本类型
 */

// 1.string字符串
let message:string="hello world"
let geeting:string=`模板字符串,${message}`
console.log("1.字符串类型"+message);
console.log("2.字符串类型"+geeting);

// 2.number数字
// 支持所有进制
let age:number=18
let temperature:number=12.34
let binary:number=0b1111
let octal:number=0o123
let hex:number=0x123
console.log("3.数字类型"+age);
console.log("4.数字类型"+temperature);
console.log("5.数字类型(2进制)"+binary);
console.log("6.数字类型(8进制)"+octal);
console.log("7.数字类型(16进制)"+hex);

// 3.布尔值boolean
let isDone:boolean=true
console.log("8.布尔类型"+isDone);

/**
 * 4数组
 * 1.使用[]
 * 2.使用数组泛型Array<元素类型>
 */
let list:number[]=[1,2,3]
let list2:Array<number>=[1,2,3]
console.log("9.数组类型"+list);
console.log("10.数组类型"+list2);

/**
 * 5元组Tuple
 * 1.表示一个一直元素数量和类型的数组,各元素的类型不必相同
 * 
 */
//只有2个元素,并且第一个元素是必是字符串,第二个元素必是数字才不会报错
let x:[string,number]
x=["hello",123]
// x=[123,"hello"] //报错
// x=[123] //报错
console.log("11.元组类型"+x);

/**
 * 6枚举enum
 * 1.默认情况下是从0开始为元素编号,也可以手动为成员编号
 */
enum Color{
    Red,
    Green,
    Blue
}
let c:Color=Color.Green
console.log("12.枚举类型"+c);

enum Color2{
    Red=1,      //1
    Green,      //2
    Blue        //3
}
let c2:Color2=Color2.Green  //如果没有手动编号依着上一个元素的编号,继续编号
console.log("13.枚举类型(如果没有手动编号依着上一个元素的编号,继续编号)"+c2);

enum Color3{
    Red=1,
    Green=2,
    Blue=4
}
let c3:Color3=Color3.Green  //手动编号,则是编号的值
console.log("14.枚举类型(手动编号,则是编号的值)"+c3);

// 由枚举的值得到它的名字
enum Color4 {
    Red,        //0
    Green,      //1
    Blue        //1
}
let colorName:string=Color4[1]
console.log("15.枚举类型(由枚举的值得到它的名字)"+colorName); //Green



/**
 * 7.任意值any
 * 在编译阶段还不清除类型时使用
 * 可以再次赋值,可以赋不同类型的值
 */
let notSure:any=4
console.log("16.任意值类型"+notSure);

notSure="maybe a string instead"
console.log("16.任意值类型"+notSure);
notSure=false
console.log("17.任意值类型"+notSure);

let list3:any[]=[1,true,"free"]
console.log("18.任意值类型"+list3);
list3[1]=100
console.log("19.任意值类型"+list3);


/**
 * 8.空值void
 * 表示没有任何类型
 * void类型的变量只能被赋值为undefined和null
 */

// 函数没有返回值
function noReturn():void{}
// 只能赋值undefined和null
let u:void=undefined
let n:void=null
console.log("20.空值类型"+u+n);

/**
 * 9.null和undefined
 * null表示一个空对象引用
 * undefined表示一个声明了但未初始化的变量
 */

let un:undefined=undefined
let nu:null=null
console.log("21.空值类型"+un+nu);

/**
 * 10.never表示不会有返回值
 * 通常用于抛出错误或进入无限循环的函数,表示该函数永远不会正常结束
 */

function throwError(message:string):never{
    throw new Error(message)
}


/**
 * unknow类型
 * 表示未知类型
 */
let notSure2:unknown=4
console.log(typeof notSure2);
notSure2="maybe a string instead"
console.log(typeof notSure2);

// 可以使用as来明确类型(不能直接将值为4的变量赋值给number类型变量)
let notSure3:unknown=4
let num:number=notSure3 as number


/**
 * 联合类型
 */
let union:string|number=4
console.log("22.联合类型"+union);
union="hello"
console.log("23.联合类型"+union);
// union=true   //报错(只能是string或number类型)

//联合类型用于数组中
let arr:number[]|string[]=[]
arr=[1,2,3]
console.log("24.联合类型"+arr);
arr=["1","2","3"]
console.log("25.联合类型"+arr);
let arr2:(number|string)[]=["1","2","3",2,5]
console.log("26.联合类型"+arr2);
let arr3:Array<number|string>=["1","2","3",2,5]
console.log("27.联合类型"+arr3);


/**
 * 对象类型
 */
type P={
    name:string,
    age:number
}
let p1:P={
    name:"张三",
    age:18
}


// 键值对类型(健为字符串类型,值为任意类型)
type P2={
    [key:string]:any
}

let p2:P2={
    name:"张三",
    age:18
}

//使用record关键字
type P3=Record<string,any>
type P4=Record<"userName"|"age",any>    //指定键值对类型(健为userName或age,值为任意类型)


/**
 * type关键字
 * 用于定义一个新类型
 */
type P5=string|number
let p5:P5="hello"